using System.Collections.Generic;
using System.Linq;
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;

using MyUtils;

namespace SolutionOrchestrator.Validators
{
	public class DelegateCommand:ObservableObject, ICommand
	{
		readonly Action _act;
		readonly Func<bool> _canExecute;
		readonly bool _useSuggestion;

		public DelegateCommand(Action act, Func<bool> canExecute = null,  Box<EventHandler> requery = null, bool useSuggestion=true)
		{
			_act = act;
			_canExecute = canExecute;
			_useSuggestion = useSuggestion;

			if (requery != null)
			{
				requery.Value += delegate
				{
					RaiseCanExecuteChanged();
				};
			}

//			if (_canExecute != null)
//			{
//				if (_useSuggestion)
//				{
//					CommandManager.RequerySuggested += OnCanExecuteStateCahnged;
//				}
//				_canExecuteChanged += OnCanExecuteStateCahnged;
//			}
		}

//		void OnCanExecuteStateCahnged(object sender, EventArgs eventArgs)
//		{
//			OnPropertyChanged("CanExecuteState");
//		}

		#region Implementation of ICommand

		public void Execute(object parameter)
		{
			try
			{
				_act();
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
			}
		}

		public bool CanExecute(object parameter)
		{
			var newState = _canExecute == null || _canExecute();
			var notify = newState != _lastState;
			_lastState = newState;
			if (notify && _lastStateConsumed)
			{
				OnPropertyChanged("CanExecuteNull");
			}
			return newState;
		}

		bool? _lastState;
		bool _lastStateConsumed;

		public bool CanExecuteNull
		{
			get
			{
				_lastStateConsumed = true;
				if (_lastState == null)
				{
					_lastState = CanExecute(null);
				}
				return _lastState.Value;
			}
		}

		public event EventHandler CanExecuteChanged
		{
			add
			{
				if (_canExecute != null)
				{
					if (_useSuggestion)
					{
						CommandManager.RequerySuggested += value;
					}
					_canExecuteChanged += value;
				}
			}
			remove
			{
				if (_canExecute != null)
				{
					if (_useSuggestion)
					{
						CommandManager.RequerySuggested -= value;
					}
					_canExecuteChanged -= value;
				}
			}
		}

		#endregion

		EventHandler _canExecuteChanged;
		public void RaiseCanExecuteChanged()
		{
			var ev = _canExecuteChanged;
			if (ev != null && _canExecute != null)
			{
				var app = Application.Current;
				if (app != null)
				{
					var disp = app.Dispatcher;
					if (disp != null)
					{
						if (Dispatcher.CurrentDispatcher != Application.Current.Dispatcher)
						{
							Application.Current.Dispatcher.BeginInvoke(ev, this, EventArgs.Empty);
						}
						else
						{
							ev(this, EventArgs.Empty);
						}
					}
				}
			}
		}
	}
}